// just build this file
// Usage:
// 前缀
//
//	.\podw.exe pull --prefix m.daocloud.io docker.io/library/ubuntu
//
// 默认
//
//	.\podw.exe pull docker.io/library/ubuntu
//
// 搜索
//
//	.\podw.exe search clickhouse
package main

import (
	_ "embed"
	"fmt"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"time"

	"github.com/spf13/cobra"
)

//go:embed mirror.txt
var mirrorContent string

var mirrorPrefix string

var rootCmd = &cobra.Command{
	Use:   "podw",
	Short: "Podw 是一个容器镜像拉取命令的包装工具",
	Long:  `Podw 会在拉取镜像前检查镜像是否在允许列表中，并自动添加镜像仓库前缀.`,
}

var pullCmd = &cobra.Command{
	Use:   "pull IMAGE",
	Short: "拉取镜像",
	Long:  `拉取镜像命令会检查镜像是否在允许列表中，并自动添加镜像仓库前缀.`,
	Args:  cobra.MinimumNArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		image := args[0]

		// 从嵌入的 mirror.txt 文件中查找镜像是否存在
		if !imageExistsInMirror(image) {
			fmt.Printf("镜像 %s 不在镜像列表中，不允许拉取\n", image)
			return
		}

		// 构造新的镜像名称，添加指定的镜像前缀
		newImage := fmt.Sprintf("%s/%s", mirrorPrefix, image)

		// 使用正则表达式检查镜像名称格式
		if !isValidImageName(newImage) {
			fmt.Printf("镜像名称格式不正确: %s\n", newImage)
			return
		}

		// 检测可用的容器运行时, not test?
		containerRuntime, err := detectContainerRuntime()
		if err != nil {
			fmt.Printf("未检测到可用的容器运行时: %v\n", err)
			return
		}

		// 执行 podman pull 命令
		fmt.Printf("正在使用%v拉取镜像 %s...\n", containerRuntime, newImage)
		podmanCmd := exec.Command(containerRuntime, "pull", newImage)

		// 获取命令的输出管道
		stdout, err := podmanCmd.StdoutPipe()
		if err != nil {
			fmt.Printf("获取输出管道失败: %v\n", err)
			return
		}
		stderr, err := podmanCmd.StderrPipe()
		if err != nil {
			fmt.Printf("获取错误管道失败: %v\n", err)
			return
		}

		// 启动计时器协程
		ticker := time.NewTicker(time.Second)
		done := make(chan bool)

		go func() {
			for {
				select {
				case <-ticker.C:
					// fmt.Printf("\r正在拉取中... 当前时间: %s", time.Now().Format("15:04:05"))
				case <-done:
					ticker.Stop()
					return
				}
			}
		}()

		// 启动命令
		if err := podmanCmd.Start(); err != nil {
			fmt.Printf("启动拉取命令失败: %v\n", err)
			done <- true
			return
		}

		// 读取并打印输出
		go func() {
			buf := make([]byte, 1024)
			for {
				n, err := stdout.Read(buf)
				if n > 0 {
					fmt.Printf("\r%s", strings.TrimSpace(string(buf[:n])))
				}
				if err != nil {
					break
				}
			}
		}()

		// 读取并打印错误
		go func() {
			buf := make([]byte, 1024)
			for {
				n, err := stderr.Read(buf)
				if n > 0 {
					fmt.Printf("\r%s", strings.TrimSpace(string(buf[:n])))
				}
				if err != nil {
					break
				}
			}
		}()

		// 等待命令完成
		if err := podmanCmd.Wait(); err != nil {
			fmt.Printf("\n拉取镜像失败: %v\n", err)
			done <- true
			return
		}

		// 停止计时器
		done <- true
		fmt.Printf("\n拉取镜像成功: %s\n", newImage)
	},
}

// 添加 search 命令
var searchCmd = &cobra.Command{
	Use:   "search KEYWORD",
	Short: "搜索镜像列表",
	Long:  "在允许的镜像列表中执行模糊搜索",
	Args:  cobra.MinimumNArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		keyword := args[0]
		results := searchImages(keyword)

		if len(results) == 0 {
			fmt.Printf("未找到包含关键词 '%s' 的镜像\n", keyword)
			return
		}

		fmt.Printf("找到 %d 个匹配的镜像:\n", len(results))
		for i, image := range results {
			fmt.Printf("[%d] %s\n", i+1, image)
		}
	},
}

func init() {
	// 添加 --prefix 标志，默认值为 m.daocloud.io
	pullCmd.Flags().StringVarP(&mirrorPrefix, "prefix", "p", "m.daocloud.io", "设置镜像仓库前缀")
	rootCmd.AddCommand(pullCmd)

	// 添加 search 命令
	rootCmd.AddCommand(searchCmd)
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

// 检查镜像是否存在于嵌入的 mirror.txt 文件中
func imageExistsInMirror(image string) bool {
	lines := strings.Split(mirrorContent, "\n")
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if line == image {
			return true
		}
	}
	return false
}

// 在镜像列表中执行模糊搜索
func searchImages(keyword string) []string {
	var results []string
	lines := strings.Split(mirrorContent, "\n")

	// 转换为小写进行不区分大小写的搜索
	keywordLower := strings.ToLower(keyword)

	for _, line := range lines {
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}

		// 检查是否包含关键词（不区分大小写）
		if strings.Contains(strings.ToLower(line), keywordLower) {
			results = append(results, line)
		}
	}

	return results
}

// 使用正则表达式验证镜像名称格式
func isValidImageName(image string) bool {
	// 常见的 Docker 镜像名称格式
	pattern := `^([a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(:[0-9]+)?/)?([a-zA-Z0-9-._]+/)*[a-zA-Z0-9-._]+$`
	matched, err := regexp.MatchString(pattern, image)
	if err != nil {
		return false
	}
	return matched
}

// 检测系统中可用的容器运行时
func detectContainerRuntime() (string, error) {
	runtimes := []string{"podman", "docker"}

	for _, runtime := range runtimes {
		_, err := exec.LookPath(runtime)
		if err == nil {
			// 验证命令是否能正常执行
			if _, err := exec.Command(runtime, "version").CombinedOutput(); err == nil {
				return runtime, nil
			}
		}
	}

	return "", fmt.Errorf("未找到可用的容器运行时，请确保安装了 podman 或 docker")
}
